package set

import (
	"bytes"
	"errors"
	"fmt"
)

//Set 接口定义
type Set interface {
	Add(e interface{}) bool
	Remove(e interface{})
	Clear()
	Contains(e interface{}) bool
	Len() int
	Same(other Set) bool
	Elements() []interface{}
	String() string
}

type HashSet struct {
	m map[interface{}]bool
}

//HashSet 初始化
func NewHashSet() *HashSet {
	return &HashSet{m: make(map[interface{}]bool)}
}

//添加元素

func (set *HashSet) Add(e interface{}) bool {
	if !set.m[e] {
		set.m[e] = true
		return true
	}
	return false
}

//删除元素
func (set *HashSet) Remove(e interface{}) {
	delete(set.m, e)
}

//清空Set中的元素
func (set *HashSet) Clear() {
	set.m = make(map[interface{}]bool)
}

//判断是否包含一个元素
func (set *HashSet) Contains(e interface{}) bool {
	return set.m[e]
}

//求元素个数
func (set *HashSet) Len() int {
	return len(set.m)
}

//判断两个Set是否相同，HashSet本身是无序的，所以只要元素相同就是相同的

func (set *HashSet) Same(other Set) bool {
	if other == nil {
		return false
	}
	if set.Len() != other.Len() {
		return false
	}
	for key := range set.m {
		if !other.Contains(key) {
			return false
		}
	}
	return true
}

//获取Set中的所有元素
//为了防止在获取元素中，另一个进程往set中添加元素而导致元素提取不全
//采用了一个处理方式

func (set *HashSet) Elements() []interface{} {
	initialLen := len(set.m)
	snapshot := make([]interface{}, initialLen)
	actualLen := 0

	for key := range set.m {
		if actualLen < initialLen {
			snapshot[actualLen] = key
		} else {
			snapshot = append(snapshot, key)
		}
		actualLen++
	}
	if actualLen < initialLen {
		snapshot = snapshot[:actualLen]
	}
	return snapshot
}

func (set *HashSet) String() string {
	var buf bytes.Buffer
	buf.WriteString("Set { ")
	for key := range set.m {
		buf.WriteString(fmt.Sprintf("%v ", key))
	}
	buf.WriteString("}")
	return buf.String()
}

//实现是否真包含的判断功能

func (set *HashSet) IsSuperset(other *HashSet) bool {
	if other == nil {
		return false
	}

	oneLen := set.Len()
	otherLen := other.Len()
	//如果两个集合相同长度，肯定不是真包含
	//set的长度为零，肯定不能包含other
	if oneLen == 0 || otherLen == oneLen {
		return false
	}
	//如果set长度大于0，并且other长度为0，肯定真包含
	if oneLen > 0 && otherLen == 0 {
		return true
	}

	for _, v := range other.Elements() {
		if !set.Contains(v) {
			return false
		}
	}
	return true
}

//实现A与B的并集

func (set *HashSet) Union(other *HashSet) (union *HashSet, err error) {
	if other == nil {
		return nil, errors.New("other is nil")
	}

	if set.Len() == 0 {
		union = other
		return
	} else if other.Len() == 0 {
		union = set
		return
	}

	union = NewHashSet()
	for _, v := range set.Elements() {
		union.Add(v)
	}
	for _, v := range other.Elements() {
		if !set.Contains(v) {
			union.Add(v)
		}
	}
	return
}

//实现A和B的交集

func (set *HashSet) Intersect(other *HashSet) (ret *HashSet, err error) {
	if other == nil {
		return nil, errors.New("other is nil")
	}
	if set.Len() == 0 {
		ret = set
		return
	} else if other.Len() == 0 {
		ret = other
		return
	}

	ret = NewHashSet()
	for _, v := range set.Elements() {
		if other.Contains(v) {
			ret.Add(v)
		}
	}
	return
}

//实现A对B的差集（只存在于A，而不存在于B的元素集合）

func (set *HashSet) Difference(other *HashSet) (diff *HashSet, err error) {
	if other == nil {
		return nil, errors.New("other is nil")
	}
	if set.Len() == 0 {
		diff = set
		return
	} else if other.Len() == 0 {
		diff = other
		return
	}

	diff = NewHashSet()
	for _, v := range set.Elements() {
		if !other.Contains(v) {
			diff.Add(v)
		}
	}
	return
}

//实现A与B的对称差集
//求A对B的差集，B对A的差集，两个差集的并集

func (set *HashSet) SymmetricDifference(other *HashSet) (ret *HashSet, err error) {
	if other == nil {
		return nil, errors.New("other is nil")
	}

	var diff1, diff2 *HashSet

	if diff1, err = set.Difference(other); err != nil {
		return nil, errors.New(err.Error())
	}
	if diff2, err = other.Difference(set); err != nil {
		return nil, errors.New(err.Error())
	}
	if ret, err = diff1.Union(diff2); err != nil {
		return nil, errors.New(err.Error())
	}
	return
}

func IsSet(v interface{}) bool{
	if _,ok := v.(Set);ok{
		return true

	}

	return false
}
